package com.ibeeking.found.common.config.async;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@ConfigurationProperties(prefix = "aysnc")
@Configuration
@EnableAsync
public class AsyncConfig {

    private String groupName;
    private String namePrefix;
    private int corePoolSize;
    private int maxPoolSize;
    private int queueCapacity;
    private int keepAliveSeconds;
    private boolean waitForTasksToCompleteOnShutdown;
    private int awaitTerminationSeconds;

    /**
     * AbortPolicy==ThreadPoolExecutor中默认的拒绝策略就是AbortPolicy。直接抛出异常。
     * CallerRunsPolicy在任务被拒绝添加后，会调用当前线程池的所在的线程去执行被拒绝的任务
     * DiscardPolicy会让被线程池拒绝的任务直接抛弃，不会抛异常也不会执行
     * DiscardOldestPolicy策略的作用是，当任务呗拒绝添加时，会抛弃任务队列中最旧的任务也就是最先加入队列的，再把这个新任务添加进去
     */

    @Bean
    public ThreadPoolTaskExecutor abortPolicyExecutor() {
        //直接抛出异常。
        ThreadPoolTaskExecutor taskExecutor = new ThreadContextPoolTaskExecutor();
        taskExecutor.setThreadGroupName(null == groupName ? "found-Task" : groupName);
        taskExecutor.setThreadNamePrefix(null == namePrefix ? "Aysnc-" : namePrefix);
        taskExecutor.setCorePoolSize(0 == corePoolSize ? Runtime.getRuntime().availableProcessors() * 2 : corePoolSize);
        taskExecutor.setMaxPoolSize(0 == maxPoolSize ? 100 : maxPoolSize);
        taskExecutor.setKeepAliveSeconds(0 == keepAliveSeconds ? 60 : keepAliveSeconds);
        taskExecutor.setQueueCapacity(0 == queueCapacity ? 20000 : queueCapacity);
        taskExecutor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        taskExecutor.setAwaitTerminationSeconds(0 == awaitTerminationSeconds ? 60 : awaitTerminationSeconds);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        return taskExecutor;
    }

    @Bean("callerRunsPolicy")
    @Primary
    public ThreadPoolTaskExecutor callerRunsPolicyExecutor() {
        //会调用当前线程池的所在的线程去执行被拒绝的任务
        ThreadPoolTaskExecutor taskExecutor = new ThreadContextPoolTaskExecutor();
        taskExecutor.setThreadGroupName(null == groupName ? "found-Task" : groupName);
        taskExecutor.setThreadNamePrefix(null == namePrefix ? "Aysnc-" : namePrefix);
        taskExecutor.setCorePoolSize(0 == corePoolSize ? Runtime.getRuntime().availableProcessors() * 2 : corePoolSize);
        taskExecutor.setMaxPoolSize(0 == maxPoolSize ? 100 : maxPoolSize);
        taskExecutor.setKeepAliveSeconds(0 == keepAliveSeconds ? 60 : keepAliveSeconds);
        taskExecutor.setQueueCapacity(0 == queueCapacity ? 20000 : queueCapacity);
        taskExecutor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        taskExecutor.setAwaitTerminationSeconds(0 == awaitTerminationSeconds ? 60 : awaitTerminationSeconds);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return taskExecutor;
    }

    @Bean("discardPolicy")
    public ThreadPoolTaskExecutor discardPolicyExecutor() {
        //会让被线程池拒绝的任务直接抛弃，不会抛异常也不会执行
        ThreadPoolTaskExecutor taskExecutor = new ThreadContextPoolTaskExecutor();
        taskExecutor.setThreadGroupName(null == groupName ? "found-Task" : groupName);
        taskExecutor.setThreadNamePrefix(null == namePrefix ? "Aysnc-" : namePrefix);
        taskExecutor.setCorePoolSize(0 == corePoolSize ? Runtime.getRuntime().availableProcessors() * 2 : corePoolSize);
        taskExecutor.setMaxPoolSize(0 == maxPoolSize ? 100 : maxPoolSize);
        taskExecutor.setKeepAliveSeconds(0 == keepAliveSeconds ? 60 : keepAliveSeconds);
        taskExecutor.setQueueCapacity(0 == queueCapacity ? 20000 : queueCapacity);
        taskExecutor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        taskExecutor.setAwaitTerminationSeconds(0 == awaitTerminationSeconds ? 60 : awaitTerminationSeconds);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        return taskExecutor;
    }

    @Bean("discardOldestPolicy")
    public ThreadPoolTaskExecutor discardOldestPolicyExecutor() {
        //会抛弃任务队列中最旧的任务也就是最先加入队列的
        ThreadPoolTaskExecutor taskExecutor = new ThreadContextPoolTaskExecutor();
        taskExecutor.setThreadGroupName(null == groupName ? "found-Task" : groupName);
        taskExecutor.setThreadNamePrefix(null == namePrefix ? "Aysnc-" : namePrefix);
        taskExecutor.setCorePoolSize(0 == corePoolSize ? Runtime.getRuntime().availableProcessors() * 2 : corePoolSize);
        taskExecutor.setMaxPoolSize(0 == maxPoolSize ? 100 : maxPoolSize);
        taskExecutor.setKeepAliveSeconds(0 == keepAliveSeconds ? 60 : keepAliveSeconds);
        taskExecutor.setQueueCapacity(0 == queueCapacity ? 20000 : queueCapacity);
        taskExecutor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        taskExecutor.setAwaitTerminationSeconds(0 == awaitTerminationSeconds ? 60 : awaitTerminationSeconds);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        return taskExecutor;
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public String getNamePrefix() {
        return namePrefix;
    }

    public void setNamePrefix(String namePrefix) {
        this.namePrefix = namePrefix;
    }

    public int getCorePoolSize() {
        return corePoolSize;
    }

    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }

    public int getMaxPoolSize() {
        return maxPoolSize;
    }

    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    public int getQueueCapacity() {
        return queueCapacity;
    }

    public void setQueueCapacity(int queueCapacity) {
        this.queueCapacity = queueCapacity;
    }

    public int getKeepAliveSeconds() {
        return keepAliveSeconds;
    }

    public void setKeepAliveSeconds(int keepAliveSeconds) {
        this.keepAliveSeconds = keepAliveSeconds;
    }

    public boolean isWaitForTasksToCompleteOnShutdown() {
        return waitForTasksToCompleteOnShutdown;
    }

    public void setWaitForTasksToCompleteOnShutdown(boolean waitForTasksToCompleteOnShutdown) {
        this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
    }

    public int getAwaitTerminationSeconds() {
        return awaitTerminationSeconds;
    }

    public void setAwaitTerminationSeconds(int awaitTerminationSeconds) {
        this.awaitTerminationSeconds = awaitTerminationSeconds;
    }
}

